package com.tbit.main.controller;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.tbit.common.constant.MethodEnum;
import com.tbit.common.constant.ModuleEnum;
import com.tbit.common.constant.OperationPlatform;
import com.tbit.common.entity.MachineOpLog;
import com.tbit.common.utils.MessageUtil;
import com.tbit.main.common.JsonResult;
import com.tbit.main.constant.OperateLog;
import com.tbit.main.constant.*;
import com.tbit.main.exception.BaseException;
import com.tbit.main.h2.pojo.ParkPoint;
import com.tbit.main.pojo.*;
import com.tbit.main.pojo.VO.BatchMoveMachineReqVO;
import com.tbit.main.pojo.VO.PutMachineRespVO;
import com.tbit.main.pojo.VO.PutMachineReqVO;
import com.tbit.main.pojo.dto.CheckMachineDTO;
import com.tbit.main.pojo.dto.ImportMachineDTO;
import com.tbit.main.remote.rpc.UQHttpClient;
import com.tbit.main.service.*;
import com.tbit.main.service.impl.MachineOpLogService;
import com.tbit.main.util.*;
import com.tbit.main.util.asc.AesTool;
import com.tbit.manager.api.UserCardApi;
import org.checkerframework.checker.units.qual.A;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.serializer.SerializationException;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.text.ParseException;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 设备
 *
 * @author Leon
 * 2019年11月11日 下午1:37:42
 */
@RestController
@RequestMapping("/machine")
public class MachineController {

    /**
     * 经纬度格式化
     */
    private DecimalFormat df = new DecimalFormat("#.######");

    @Autowired
    private MachineService machineService;
    @Autowired
    private MachineStatusService machineStatusService;
    @Autowired
    private TokenService tokenService;
    @Autowired
    private MachineBorrowService machineBorrowService;
    @Autowired
    private TerControlService terControlService;
    @Autowired
    private MainFinishOrderLogService mainFinishOrderLogService;
    @Autowired
    private CalibrateService calibrateService;
    @Autowired
    private CodeChangeLogService codeChangeLogService;
    @Autowired
    private MachineFaultService machineFaultService;
    @Autowired
    private UserService userService;
    @Autowired
    private AccountService accountService;
    @Autowired
    private RedisService redisService;
    @Autowired
    private OrderLogService orderLogService;
    @Autowired
    private BatteryService batteryService;
    @Autowired
    private DataService dataService;
    @Autowired
    private RideLogService rideLogService;
    @Autowired
    private MachineAttrService machineAttrService;
    @Autowired
    private MachineOpLogService machineOpLogService;
    @Autowired
    private UserCardApi userCardApi;

    /**
     * 获取站点内设备列表
     */
    @RequestMapping("/getByParkPointId")
    public JsonResult getByParkPointId(String token, Integer parkPointId) {
        /* 校验 */
        Assert.notNull(parkPointId, "ParkPoint.id.notNull");

        List<Machine> machines = machineService.getByParkPointId(parkPointId);

        return JsonResult.succ(machines);
    }

    /**
     * 投放车辆
     */
    @RequestMapping("/parkPointPut")
    @OperateLog(module = ModuleEnum.MACHINE, methods = MethodEnum.MACHINE_PUT)
    public JsonResult parkPointPut(String token, Integer parkPointId, String userCode) {
        AccountUser accountUserToken = tokenService.getAccount(token);

        /* 校验 */
        Assert.notNull(parkPointId, "ParkPoint.id.notNull");
        Assert.hasLength(userCode, "Machine.userCode.notNull");

        /**查询设备信息*/
        Machine machine = machineService.getByUseCode(userCode);
        if (machine == null) {
            throw new BaseException("Machine.notExist");
        }

        /**设备权限判断*/
        machineService.auth(accountUserToken.getAgents(), machine.getMachineId());

        /** 排除运维故障车辆*/
        MachineFault machineFault = machineFaultService.getByMachineId(machine.getMachineId());
        if (machineFault != null && machineFault.getFrom().equals(0)) {
            throw new BaseException("Machine.fault.make.not");
        }

        Integer inside = null;
        MachineStatus machineStatus = machineStatusService.getByMachineId(machine.getMachineId());
        if (machineStatus != null) {
            List<Point> points = dataService.getParkList(parkPointId);
            if (CollUtil.isNotEmpty(points)) {
                boolean inPoly = GeoUtil.IsPtInPoly(new Point(machineStatus.getLon(), machineStatus.getLat()), points);
                if (inPoly) {
                    inside = 1;
                } else {
                    ParkPoint parkPoint1 = dataService.getParkPoint(parkPointId);
                    Double distance = GeoUtil.getDistance(new Point(machineStatus.getLon(), machineStatus.getLat()), points);
                    if (distance <= parkPoint1.getAllowRange()) {
                        inside = 1;
                    } else {
                        inside = 0;
                    }
                }
            }
        }


        machineService.putMachine(new ParkMachine(parkPointId, machine.getMachineId(), inside));

        // 插入车辆操作日志
        machineOpLogService.insertSingle(MachineOpLog.builder()
                .accountId(machine.getAccountId())
                .machineId(machine.getMachineId())
                .machineNO(machine.getMachineNO())
                .userCode(machine.getUserCode())
                .operation("车辆投放")
                .opType("上架")
                .opUser(accountUserToken.getName())
                .opUserPhone(accountUserToken.getPhone())
                .opPlatform(OperationPlatform.MAINTAIN.code)
                .result(true)
                .opTime(LocalDateTime.now())
                .build());

        return JsonResult.succ();
    }

    /**
     * 取消投放
     */
    @RequestMapping("/parkPointRecovery")
    @OperateLog(module = ModuleEnum.MACHINE, methods = MethodEnum.MACHINE_NOT_PUT)
    public JsonResult parkPointRecovery(String token, String userCode) {
        AccountUser accountUserToken = tokenService.getAccount(token);

        /* 校验 */
        Assert.hasLength(userCode, "Machine.userCode.notNull");

        /**查询设备信息*/
        Machine machine = machineService.getByUseCode(userCode);
        if (machine == null) {
            throw new BaseException("Machine.notExist");
        }

        /**设备权限判断*/
        machineService.auth(accountUserToken.getAgents(), machine.getMachineId());

        machineService.recovery(machine.getMachineId());

        // 插入车辆操作日志
        machineOpLogService.insertSingle(MachineOpLog.builder()
                .accountId(machine.getAccountId())
                .machineId(machine.getMachineId())
                .machineNO(machine.getMachineNO())
                .userCode(machine.getUserCode())
                .operation("车辆投放")
                .opType("下架")
                .opUser(accountUserToken.getName())
                .opUserPhone(accountUserToken.getPhone())
                .opPlatform(OperationPlatform.MAINTAIN.code)
                .result(true)
                .opTime(LocalDateTime.now())
                .build());

        return JsonResult.succ();
    }

    /**
     * 修改车辆状态
     */
    @RequestMapping("/changeState")
    @OperateLog(module = ModuleEnum.MACHINE, methods = MethodEnum.MACHINE_UPDATE_STATE)
    public JsonResult changeState(String token, String userCode, Integer state) {
        AccountUser accountUserToken = tokenService.getAccount(token);

        /* 校验 */
        Assert.hasLength(userCode, "Machine.userCode.notNull");
        Assert.notNull(state, "Machine.state.notNull");

        /**查询设备信息*/
        Machine machine = machineService.getByUseCode(userCode);
        if (machine == null) {
            throw new BaseException("Machine.notExist");
        }

        /**排除未投放车辆*/
        if (machine.getState().equals(MachineStateConstant.MACHINE_STATE_DTF)) {
            throw new BaseException("Machine.state.notChange");
        }

        /**排除故障车辆*/
        if (machine.getState().equals(MachineStateConstant.MACHINE_STATE_GZ)) {
            throw new BaseException("Machine.fault.make.not");
        }

        /**设备权限判断*/
        machineService.auth(accountUserToken.getAgents(), machine.getMachineId());

        machineService.changeState(machine.getMachineId(), state);
        LogUtil.info("更改车辆状态：人员：" + accountUserToken.getAccountUserId() + " 车辆：" + machine.getMachineId() + " 状态：" + state);
        return JsonResult.succ();
    }


    /**
     * 修改车辆状态
     */
    @RequestMapping("/changeStateBatch")
    @OperateLog(module = ModuleEnum.MACHINE, methods = MethodEnum.MACHINE_UPDATE_STATE)
    public JsonResult changeStateBatch(String token, @RequestParam("userCodeS") List<String> userCodeS) {
        AccountUser accountUserToken = tokenService.getAccount(token);
        if (userCodeS.size() < 1){
            throw new BaseException("userCodeS.notExist");
        }
        machineService.changeStateBatch(userCodeS);
        LogUtil.info("更改车辆状态：人员：" + accountUserToken.getAccountUserId() + " 车辆编码：" + userCodeS+" 状态： 代投放" );

        // 插入车辆操作日志
        List<Machine> machines = machineService.getByUserCodes(userCodeS);
        List<MachineOpLog> machineOpLogList = machines.stream()
                .map(machine -> MachineOpLog.builder()
                        .accountId(machine.getAccountId())
                        .machineId(machine.getMachineId())
                        .machineNO(machine.getMachineNO())
                        .userCode(machine.getUserCode())
                        .operation("车辆投放")
                        .opType("下架")
                        .opUser(accountUserToken.getName())
                        .opUserPhone(accountUserToken.getPhone())
                        .opPlatform(OperationPlatform.MAINTAIN.code)
                        .result(true)
                        .opTime(LocalDateTime.now())
                        .build())
                .collect(Collectors.toList());
        machineOpLogService.insertBatch(machineOpLogList);

        return JsonResult.succ();
    }

    /**
     * 获取车辆信息
     */
    @RequestMapping("/getMachineInfo")
    public JsonResult getMachineInfo(String token, Integer machineId, Integer mapType) throws ParseException {
        AccountUser accountUserToken = tokenService.getAccount(token);

        /* 校验 */
        Assert.notNull(machineId, "Machine.machineId.notNull");

        if (mapType == null) {
            mapType = SysConstant.GOOGLE;
        }

        /**设备权限判断*/
        machineService.auth(accountUserToken.getAgents(), machineId);

        MachineInfo machineInfo = machineService.getMachineInfo(machineId);

        /**校准经纬度*/
        if (machineInfo.getMachineStatus() != null) {
            Point point = new Point(Double.parseDouble(df.format(machineInfo.getMachineStatus().getLon())), Double.parseDouble(df.format(machineInfo.getMachineStatus().getLat())));
            point = calibrateService.commonCalibrate(point, MapConstant.MAP_ORI, mapType);
            machineInfo.getMachineStatus().setLonC(point.getX());
            machineInfo.getMachineStatus().setLatC(point.getY());
        }

        return JsonResult.succ(machineInfo);
    }

    /**
     * 根据设备编号查询
     */
    @RequestMapping("/getByMachineNO")
    public JsonResult getByMachineNO(String token, String machineNO) {
        AccountUser accountUserToken = tokenService.getAccount(token);

        /* 校验 */
        Assert.hasLength(machineNO, "Machine.machineNO.notNull");

        Machine machine = machineService.getByMachineNO(machineNO);

        if (machine == null) {
            throw new BaseException("Machine.notExist");
        }

        /**设备权限判断*/
        machineService.auth(accountUserToken.getAgents(), machine.getMachineId());

        /**查询电池编号*/
		/*BatteryMachine batteryMachine = batteryMachineService.getByMachineId(machine.getMachineId());
		if(batteryMachine!=null){
			machine.setBatteryNO(batteryMachine.getBatterNO());
		}*/
        Battery battery = batteryService.getByMachineId(machine.getMachineId());
        if (battery != null) {
            machine.setBatteryNO(battery.getBatteryNO());
        }

        return JsonResult.succ(machine);
    }

    /**
     * 根据设备编号查询
     */
    @RequestMapping("/getByUserCode")
    public JsonResult getByUserCode(String token, String userCode) {
        AccountUser accountUserToken = tokenService.getAccount(token);

        /* 校验 */
        Assert.hasLength(userCode, "Machine.userCode.notNull");

        /**查询设备信息*/
        Machine machine = machineService.getByUseCode(userCode);
        if (machine == null) {
            throw new BaseException("Machine.notExist");
        }

        /**设备权限判断*/
        machineService.auth(accountUserToken.getAgents(), machine.getMachineId());

        Battery battery = batteryService.getByMachineId(machine.getMachineId());
        if (battery != null) {
            machine.setBatteryNO(battery.getBatteryNO());
        }

        MachineStatus machineStatus = machineStatusService.getByMachineId(machine.getMachineId());
        if (machineStatus == null) {
            throw new BaseException("Machine.notActive");
        }
        machine.setSocPercent(machineStatus.getSocPercent());

        return JsonResult.succ(machine);
    }

    /**
     * 获取蓝牙连接密钥
     */
    @RequestMapping("/getBleSecret")
    public JsonResult getBleSecret(String token, String userCode) {
        AccountUser accountUserToken = tokenService.getAccount(token);

        /* 校验 */
        Assert.hasLength(userCode, "Machine.userCode.notNull");

        LogUtil.info("用户[" + accountUserToken.getPhone() + "]获取设备[" + userCode + "]蓝牙连接密钥");

        /**查询设备信息*/
        Machine machine = machineService.getByUseCode(userCode);
        if (machine == null) {
            throw new BaseException("Machine.notExist");
        }

        /**设备权限判断*/
        machineService.auth(accountUserToken.getAgents(), machine.getMachineId());
        Map<String, Object> result = new HashMap<String, Object>();
        /**兼容小安设备，获取蓝牙密钥*/
        if (machine.getMachineNO().length() > 9) {
            MachineEvent machineEvent = machineAttrService.getMachineEvent(machine.getMachineNO(), "tBTToken");
            if (machineEvent == null) {
                String secret = AesTool.Genkey(SysConstant.BLE_KEY, machine.getMachineNO());
                result.put("secret", secret);
            } else {
                result.put("secret", machineEvent.getEventValue());
            }
        } else {
            String secret = AesTool.Genkey(SysConstant.BLE_KEY, machine.getMachineNO());
            result.put("secret", secret);
        }

        result.put("machineNO", machine.getMachineNO());
        result.put("userCode", machine.getUserCode());
        result.put("machineType", machine.getMachineType());
        LogUtil.info("result:" + result.toString());
        return JsonResult.succ(result);
    }

    /**
     * 根据用户码设备状态
     */
    @RequestMapping("/getStatusByUserCode")
    public JsonResult getStatusByUserCode(String token, String userCode, Integer mapType) {
        AccountUser accountUserToken = tokenService.getAccount(token);
        /* 校验 */
        Assert.hasLength(userCode, "Machine.userCode.notNull");

        if (mapType == null) {
            mapType = SysConstant.GOOGLE;
        }

        /**查询设备信息*/
        Machine machine = machineService.getByUseCode(userCode);
        if (machine == null) {
            throw new BaseException("Machine.notExist");
        }

        /**设备权限判断*/
        machineService.auth(accountUserToken.getAgents(), machine.getMachineId());

        MachineStatus machineStatus = machineStatusService.getByMachineId(machine.getMachineId());
        /**校准经纬度*/
        if (machineStatus != null) {
            machineStatus.setFrame(machine.getFrame());
            machineStatus.setLicense(machine.getLicense());
            machineStatus.setMotor(machine.getMotor());
            machineStatus.setRemark(machine.getRemark());
            Point point = new Point(machineStatus.getLon(), machineStatus.getLat());
            calibrateService.commonCalibrate(point, MapConstant.MAP_ORI, mapType);
            machineStatus.setLonC(point.getX());
            machineStatus.setLatC(point.getY());

            /**用户码、中控码*/
            machineStatus.setUserCode(machine.getUserCode());
            machineStatus.setMachineNO(machine.getMachineNO());
        } else {
            throw new BaseException("Machine.notActive");
        }

        /**查询电池编号*/
		/*BatteryMachine batteryMachine = batteryMachineService.getByMachineId(machine.getMachineId());
		if(batteryMachine!=null){
			machineStatus.setBatteryNO(batteryMachine.getBatterNO());
		}*/

        Battery battery = batteryService.getByMachineId(machine.getMachineId());
        if (battery != null) {
            machineStatus.setBatteryNO(battery.getBatteryNO());
        }

        MachineBorrow machineBorrow = machineBorrowService.getByMachineId(machine.getMachineId());
        if (machineBorrow == null) {
            machineStatus.setInUse(0);
        } else {
            machineStatus.setInUse(1);
        }

        /**挪车*/
        String moveLogString = null;
        try {
            moveLogString = redisService.get(RedisConstant.REDIS_TER_BIKE_MOVE + machine.getMachineNO());
        } catch (SerializationException e) {
            redisService.del(RedisConstant.REDIS_TER_BIKE_MOVE + machine.getMachineNO());
        }

        if (moveLogString != null) {
            machineStatus.setMoveState(1);
        }

        /**调度*/
        String dispatchLogString = null;
        try {
            dispatchLogString = redisService.get(RedisConstant.REDIS_TER_BIKE_DISPATCH + machine.getMachineNO());
        } catch (SerializationException e) {
            redisService.del(RedisConstant.REDIS_TER_BIKE_DISPATCH + machine.getMachineNO());
        }

        if (dispatchLogString != null) {
            machineStatus.setMoveState(2);
        }

        return JsonResult.succ(machineStatus);
    }

    /**
     * 获取当前借车用户信息
     */
    @RequestMapping("/getBorrowingMachine")
    public JsonResult getBorrowingMachine(String token,
                                          @RequestParam(value = "userCode", required = false) String userCode,
                                          @RequestParam(value = "codePhone", required = false) String codePhone) throws ParseException {
        AccountUser accountUserToken = tokenService.getAccount(token);

        Machine machine = new Machine();

        if (userCode != null) {
            /**查询设备信息*/
            machine = machineService.getByUseCode(userCode);
            if (machine == null) {
                throw new BaseException("Machine.notExist");
            }

            /**判断设备是否正在骑行*/
            MachineBorrow machineBorrow = machineBorrowService.getByMachineId(machine.getMachineId());
            if (machineBorrow == null) {
                throw new BaseException("Machine.rent.not");
            }
        } else {
            if (!PhoneUtil.isPhone(codePhone)) {
                machine = machineService.getByUseCode(codePhone);
                if (machine == null) {
                    throw new BaseException("Machine.notExist");
                } else {
                    /**判断设备是否正在骑行*/
                    MachineBorrow machineBorrow = machineBorrowService.getByMachineId(machine.getMachineId());
                    if (machineBorrow == null) {
                        throw new BaseException("Machine.rent.not");
                    }
                }
            } else {
                Integer account = accountService.getByAccountAndType(accountUserToken.getAccountId(), 1).getAccountId();
                User user = userService.getByPhone(account, codePhone);
                if (user != null) {
                    MachineBorrow machineBorrow = machineBorrowService.getByUserId(user.getUserId());
                    if (machineBorrow != null) {
                        machine = machineService.getByMachineId(machineBorrow.getMachineId());
                    } else {
                        throw new BaseException("Machine.rent.not");
                    }
                } else {
                    throw new BaseException("AccountUser.notExist");
                }
            }
        }

        /**设备权限判断*/
        machineService.auth(accountUserToken.getAgents(), machine.getMachineId());

        MachineInfo machineInfo = machineService.getMachineInfo(machine.getMachineId());

        /**查询预估金额*/
        if (machineInfo != null) {
            Integer money = UQHttpClient.getOrderMoney(machineInfo.getRideLog().getUserId());
            machineInfo.getRideLog().setMoney(money / 100.0);
        }

        /**查询电池编号*/
		/*BatteryMachine batteryMachine = batteryMachineService.getByMachineId(machine.getMachineId());
		if(batteryMachine!=null){
			machineInfo.getMachine().setBatteryNO(batteryMachine.getBatterNO());
		}*/

        Battery battery = batteryService.getByMachineId(machine.getMachineId());
        if (battery != null) {
            machineInfo.getMachine().setBatteryNO(battery.getBatteryNO());
        }

        return JsonResult.succ(machineInfo);
    }


    /**
     * 获取有效卡券
     * @param userId    用户id
     * @param accountId 区域id
     * @return  Result<Map<String, Object>>
     */
    @GetMapping("/getEfficientCard")
    public Result<Map<String, Object>> getEfficientCard(Integer userId, Integer accountId){
        Assert.notNull(userId, "用户id不能为空");
        Assert.notNull(accountId, "区域id不能为空");
        return Result.success(userCardApi.getEfficientCard(userId, accountId));
    }


    /**
     * 强制结束订单
     */
    @RequestMapping("/finishOrder")
    @OperateLog(module = ModuleEnum.MACHINE, methods = MethodEnum.MACHINE_FINISHORDER)
    public JsonResult finishOrder(String token, String userCode, Double money, String remark, Integer accountId, Integer rideCardId, Integer vipId, Integer couponUserId) {
        AccountUser accountUserToken = tokenService.getAccount(token);

        /* 校验 */
        Assert.hasLength(userCode, "Machine.userCode.notNull");
        Assert.notNull(money, "Machine.money.notNull");
        Assert.hasLength(remark, "System.remark.notNull");

        /**查询设备信息*/
        Machine machine = machineService.getByUseCode(userCode);
        if (machine == null) {
            throw new BaseException("Machine.notExist");
        }

        /**设备权限判断*/
        machineService.auth(accountUserToken.getAgents(), machine.getMachineId());

        /**判断设备是否正在骑行*/
        MachineBorrow machineBorrow = machineBorrowService.getByMachineId(machine.getMachineId());
        if (machineBorrow == null) {
            throw new BaseException("Machine.rent.not");
        }

        String cleanText = remark.replaceAll("[\\x{1F600}-\\x{1F64F}\\x{1F300}-\\x{1F5FF}\\x{1F680}-\\x{1F6FF}\\x{2600}-\\x{26FF}\\x{2700}-\\x{27BF}]", "");
        /**结束订单*/
        BigDecimal bigDecimal = new BigDecimal(money);
        bigDecimal = bigDecimal.multiply(new BigDecimal("100")).setScale(0, BigDecimal.ROUND_HALF_UP);

        rideLogService.finishOrder(accountUserToken, new FinishOrderDTO(machineBorrow.getUserId(), bigDecimal.longValue(), "运维人工结束订单," + cleanText, 2, 1),
                accountId, rideCardId, vipId, couponUserId
                );

        /**发送指令锁车*/
        String serNO = UUID.randomUUID().toString();
        terControlService.sendControl(serNO, machine.getMachineNO(), "control", ControlTypeConstant.CONTROL_TYPE_LOCK, "");

        /**添加强制结束订单日志*/
        MainFinishOrderLog mainFinishOrderLog = new MainFinishOrderLog();
        mainFinishOrderLog.setAccountId(machine.getAccountId());
        mainFinishOrderLog.setMainUserId(accountUserToken.getAccountUserId());
        mainFinishOrderLog.setMainUserName(accountUserToken.getName());
        mainFinishOrderLog.setMoney(money);
        mainFinishOrderLog.setUserCode(machine.getUserCode());
        mainFinishOrderLog.setMachineNO(machine.getMachineNO());
        mainFinishOrderLog.setRemark(cleanText);
        mainFinishOrderLogService.insert(mainFinishOrderLog);


        /**远程指令日志*/
        OrderLog orderLog = new OrderLog();
        orderLog.setMachineId(machine.getMachineId());
        orderLog.setMachineNo(machine.getMachineNO());
        orderLog.setUserCode(machine.getUserCode());
        orderLog.setOpType(accountUserToken.getAccountUserType());
        orderLog.setOpId(accountUserToken.getAccountUserId());
        orderLog.setAccountUserId(accountUserToken.getAccountUserId());
        orderLog.setOpTime(DateTimeUtil.getNowTime());
        orderLog.setChannelType(0);
        orderLog.setBusinessType(1);
        orderLog.setOrderType(ControlTypeConstant.CONTROL_TYPE_CONTROL);
        orderLog.setOrderSerNo(serNO);
        orderLog.setOrderSource(8);
        orderLog.setOrderContent(ControlTypeConstant.CONTROL_TYPE_LOCK);
        orderLog.setRemark(cleanText + "运维人工结束订单");
        orderLogService.insert(orderLog);
        LogUtil.info("运维[" + accountUserToken.getPhone() + "][" + machine.getMachineNO() + "]强制结束订单");

        // 插入车辆操作日志
        machineOpLogService.insertSingle(MachineOpLog.builder()
                .accountId(machine.getAccountId())
                .machineId(machine.getMachineId())
                .machineNO(machine.getMachineNO())
                .userCode(machine.getUserCode())
                .operation("关锁还车")
                .opType("人工还车")
                .opUser(accountUserToken.getName())
                .opUserPhone(accountUserToken.getPhone())
                .opPlatform(OperationPlatform.MAINTAIN.code)
                .result(true)
                .detail("指令流水号: " + serNO + "\n骑行单号: " + machineBorrow.getOrderNO())
                .opTime(LocalDateTime.now())
                .build());

        return JsonResult.succ();
    }


    /**
     * 绑定信息修改
     */
    @RequestMapping("/boundUpdate")
    @OperateLog(module = ModuleEnum.MACHINE, methods = MethodEnum.MACHINE_BOUNDUPDATE)
    public JsonResult boundUpdate(String token, Integer machineId, String userCode, String machineNO,
                                  String frame, String license, String motor, String remark) {
        AccountUser accountUserToken = tokenService.getAccount(token);

        /* 校验 */
        Assert.notNull(machineId, "Machine.machineId.notNull");

        if (StrUtil.isNotBlank(remark) && remark.length() > 50) {
            throw new BaseException(MessageUtil.get("length.max", "备注", "50"));
        }

        /**查询设备信息*/
        Machine machine = machineService.getByMachineId(machineId);
        if (machine == null) {
            throw new BaseException("Machine.notExist");
        }

        /**权限判断*/
        machineService.auth(accountUserToken.getAgents(), machine.getMachineId());

        /**修改用户码*/
        if (userCode != null && !userCode.equals(machine.getUserCode())) {
            Machine machineUserCode = machineService.getByUseCode(userCode);
            if (machineUserCode != null) {
                throw new BaseException("Machine.userCode.exist");
            }
        }

        /**修改中控码*/
        if (machineNO != null && !machineNO.equals(machine.getMachineNO())) {
            Machine machineMachineNO = machineService.getByMachineNO(machineNO);
            if (machineMachineNO != null) {
                throw new BaseException("Machine.machineNO.exist");
            }
        }

        /**修改车架号*/
        if (frame != null && !frame.equals("") && !frame.equals(machine.getFrame())) {
            Machine machineMachineNO = machineService.getFLM(frame, null, null);
            if (machineMachineNO != null) {
                throw new BaseException("Machine.frame.exist");
            }
        }

        /**修改车牌号*/
        if (license != null && !license.equals("") && !license.equals(machine.getLicense())) {
            Machine machineMachineNO = machineService.getFLM(null, license, null);
            if (machineMachineNO != null) {
                throw new BaseException("Machine.license.exist");
            }
        }

        /**修改电机号*/
        if (motor != null && !motor.equals("") && !motor.equals(machine.getMotor())) {
            Machine machineMachineNO = machineService.getFLM(null, null, motor);
            if (machineMachineNO != null) {
                throw new BaseException("Machine.motor.exist");
            }
        }


        /**记录修改日志*/
        CodeChangeLog ccl = new CodeChangeLog();
        ccl.setAccountId(machine.getAccountId());
        ccl.setAccountUserId(accountUserToken.getAccountUserId());
        ccl.setAccountUserName(accountUserToken.getName());
        ccl.setChangeTime(DateTimeUtil.getNowTime());
        ccl.setMachineId(machine.getMachineId());
        ccl.setOldUserCode(machine.getUserCode());
        ccl.setNewUserCode(userCode);
        ccl.setOldMachineNO(machine.getMachineNO());
        ccl.setNewMachineNO(machineNO);
        ccl.setRemark("备注");
        codeChangeLogService.insert(ccl);

        LogUtil.info("修改车辆信息老：" + machine.toString());

        machineService.boundUpdate(machineId, userCode == null ? machine.getUserCode() : userCode, machineNO == null ? machine.getMachineNO() : machineNO,
                frame, license, motor, remark);

        Machine machineN = machineService.getByMachineId(machineId);
        LogUtil.info("修改车辆信息新：" + machineN.toString());

        // 插入车辆操作日志
        if (userCode != null && !userCode.equals(machine.getUserCode())) {
            machineOpLogService.insertSingle(MachineOpLog.builder()
                    .accountId(machine.getAccountId())
                    .machineId(machine.getMachineId())
                    .machineNO(machine.getMachineNO())
                    .userCode(machine.getUserCode())
                    .operation("车辆编号")
                    .opType("变更")
                    .opUser(accountUserToken.getName())
                    .opUserPhone(accountUserToken.getPhone())
                    .opPlatform(OperationPlatform.MAINTAIN.code)
                    .result(true)
                    .detail("变更前编号: " + machine.getUserCode() + "\n变更后编号: " + userCode)
                    .opTime(LocalDateTime.now())
                    .build()
            );
        }
        if (machineNO != null && !machineNO.equals(machine.getMachineNO())) {
            machineOpLogService.insertSingle(MachineOpLog.builder()
                    .accountId(machine.getAccountId())
                    .machineId(machine.getMachineId())
                    .machineNO(machine.getMachineNO())
                    .userCode(machine.getUserCode())
                    .operation("中控编号")
                    .opType("变更")
                    .opUser(accountUserToken.getName())
                    .opUserPhone(accountUserToken.getPhone())
                    .opPlatform(OperationPlatform.MAINTAIN.code)
                    .result(true)
                    .detail("变更前编号: " + machine.getMachineNO() + "\n变更后编号: " + machineNO)
                    .opTime(LocalDateTime.now())
                    .build()
            );
        }

        return JsonResult.succ();
    }

    /**
     * 实时获取车辆状态
     */
    @RequestMapping("/newState")
    public JsonResult newState(String token, String userCode) {

        Assert.hasLength(userCode, "Machine.userCode.notNull");

        AccountUser accountUserToken = tokenService.getAccount(token);
        /**查询设备信息*/
        Machine machine = machineService.getByUseCode(userCode);
        if (machine == null) {
            throw new BaseException("Machine.notExist");
        }

        /**设备权限判断*/
        machineService.auth(accountUserToken.getAgents(), machine.getMachineId());

        /**发送指令查询车辆状态*/
        String serNO = UUID.randomUUID().toString();
        terControlService.sendControl(serNO, machine.getMachineNO(), ControlTypeConstant.CONTROL_TYPE_GET, "DEVICESTATUS", "");

        Map<String, Object> map = new HashMap<>();
        map.put("serNO", serNO);
        map.put("time", DateTimeUtil.getNowTime());

        return JsonResult.succ(map);
    }

    /**
     * 获取区域内所有的车辆信息
     */
    @RequestMapping("/getByAccountId")
    public JsonResult getByAccountId(String token, Integer accountId) {
        Assert.notNull(accountId, "AccountUser.agentId.notNull");

        List<Machine> machines = machineService.getByAccountId(accountId);

        return JsonResult.succ(machines);

    }


    /**
     * 获取蓝牙连接密钥
     */
    @RequestMapping("/getSecret")
    public JsonResult getSecret(String token, String userCode) {
        AccountUser accountUserToken = tokenService.getAccount(token);

        /* 校验 */
        Assert.hasLength(userCode, "Machine.userCode.notNull");

        LogUtil.info("用户[" + accountUserToken.getPhone() + "]获取设备[" + userCode + "]蓝牙连接密钥");

        String secret = AesTool.Genkey(SysConstant.BLE_KEY, userCode);

        return JsonResult.succ(secret);
    }


    /**
     * 扫码或输入划拨的设备
     */
    @PostMapping("/putMoveMachine")
    public JsonResult<List<PutMachineRespVO>> putMoveMachine(@Valid PutMachineReqVO reqVO) {
        return JsonResult.succ(machineService.putMachine(reqVO));
    }


    /**
     * 批量划拨设备
     *
     */
    @PostMapping("/batchMoveMachine")
    @OperateLog(module = ModuleEnum.MACHINE, methods = MethodEnum.MACHINE_BATCH_MOVE)
    public JsonResult<List<PutMachineRespVO>> batchMoveMachine(@Valid BatchMoveMachineReqVO reqVO) {
        return JsonResult.succ(machineService.batchMoveMachine(reqVO));
    }


    /**
     * 校验设备信息
     * @param dto dto
     * @return Result
     */
    @PostMapping("/checkMahcine")
    public Result<Object> checkMachine(CheckMachineDTO dto){
        return machineService.checkMachine(dto);
    }


    /**
     * 批量导入设备
     * @param dto dto
     * @return Result<List<String>>
     */
    @PostMapping("/importMachine")
    public Result<List<String>> importMachine(String token, @RequestBody ImportMachineDTO dto) {
        AccountUser account = tokenService.getAccount(token);
        if (dto.getCheckMachineDTOList().size() != new HashSet<>(dto.getCheckMachineDTOList()).size()){
            return Result.error("存在重复数据，请确认后在导入");
        }
        return machineService.importMachine(dto, account);
    }

    /**
     * @description: 检查车辆编码是否正确，同时检查车辆是否属于当前区域
     * @author: mo.shanyong
     * @date: 2025/1/15 14:00
     * @param: accountId 区域id
     * @param: userCode 车辆编号
     * @return: com.tbit.main.common.JsonResult
     */
    @RequestMapping("/checkMachineAccount")
    public JsonResult checkMachineAccount(Integer accountId,String userCode){
        Assert.notNull(accountId,"区域id不能为空");
        Assert.notNull(userCode,"车辆编码不能为空");
        Machine machine = machineService.getByUseCode(userCode);
        //车辆不在当前运营区或车辆不存在
        if (Objects.isNull(machine) || !Objects.equals(machine.getAccountId(),accountId)){
            throw new BaseException("车辆不存在");
        }
        return JsonResult.succ(machine);
    }

    /**
     * @description: 获取车辆全部信息，包括最新一条换电、挪车、调度等信息
     * @author: mo.shanyong
     * @date: 2025/4/18 14:58
     * @param: token
     * @param: machineId
     * @param: mapType
     * @return: com.tbit.main.common.JsonResult
     */
    @RequestMapping("/getMachineInfoV2")
    public JsonResult getMachineInfoV2(String token, Integer machineId, Integer mapType){
        AccountUser accountUserToken = tokenService.getAccount(token);

        /* 校验 */
        Assert.notNull(machineId, "Machine.machineId.notNull");

        if (mapType == null) {
            mapType = SysConstant.GOOGLE;
        }

        /**设备权限判断*/
        machineService.auth(accountUserToken.getAgents(), machineId);

        MachineInfo machineInfo = machineService.getMachineInfoV2(machineId);

        /**校准经纬度*/
        if (machineInfo.getMachineStatus() != null) {
            Point point = new Point(Double.parseDouble(df.format(machineInfo.getMachineStatus().getLon())), Double.parseDouble(df.format(machineInfo.getMachineStatus().getLat())));
            point = calibrateService.commonCalibrate(point, MapConstant.MAP_ORI, mapType);
            machineInfo.getMachineStatus().setLonC(point.getX());
            machineInfo.getMachineStatus().setLatC(point.getY());
        }

        return JsonResult.succ(machineInfo);
    }

}